import axios, {AxiosError,type  AxiosInstance, type AxiosResponse, type Canceler, type InternalAxiosRequestConfig,} from 'axios'
import { showNotify,showConfirmDialog   } from 'vant';
import {useRouter} from 'vue-router'

// 在你的组件或拦截器中使用
const router = useRouter()

// 定义一个 不确定是什么类型 但一定是个数组的 类型
type NestedArray = number[] | string[] | object[] | NestedArray[]

// function ElMessage(param: { duration: number; showClose: boolean; type: string; message: string }) {
//
// }

// 创建一个管理axios的类
export class Interceptors {
  // 请求接口配置 默认空数组 内含 四个字段
  requestQueue: {
    createTime: number // 请求创建时间戳
    url: string // 请求接口地址
    method: string // 请求方法（GET、POST等）
    params: object | NestedArray // 请求的查询参数对象或数组
    data: object | NestedArray // 请求体数据对象或数组
    cancel: Canceler // 取消请求的函数
  }[] = []
  instance: AxiosInstance // axios实例
  // 初始化实例  相当于生命周期中的 created 函数
  constructor() {
    // 创建一个 axios 实例
    this.instance = axios.create({
      baseURL: import.meta.env.VITE_APP_BASE_API,
      timeout: 60000,
    })

    this.init()
  }

  // 初始化
  init() {
    // ========================================================================== 响应拦截器 - 开始 ==========================================================================
    this.instance.interceptors.request.use(
      (config: InternalAxiosRequestConfig) => {
        // 请求成功处理
        config.duplicateRequestValidationTime =
          import.meta.env.VITE_APP_PREVENT_DUPLICATE_SUBMISSIONS // 设置防止重复请求时间

        // 添加请求头
        const token = localStorage.getItem('USER_TOKEN')

        if (token) {
          config.headers['token'] = token
        }

        // 防止一个接口在没有响应之前进行重新提交即重复提交验证，默认不校验 duplicateRequestValidation为true时开启
        if (config.url && config.duplicateRequestValidation) {
          this.removeRequestQueue(config) // 移除重复请求的接口

          this.addRequestQueue(config) // 新增最新请求的接口
        }

        return config
      },
      (error: any) => {
        if (error.response.data) {
          // 结构 code码 msg提示信息
          const {code, message} = error.response.data
          // 判断token是否过期 以后端返回的 code 为准
          if (code === 10021) {
            this.handleTokenExpiration() // 登出事件
          }else {
            showNotify(message || '系统出错')
          }
        }
        // 请求出错处理
        Promise.reject(error)
      }
    )
    // ========================================================================== 响应拦截器 - 结束 ============================================================================

    // ========================================================================== 请求拦截器 - 开始 ==========================================================================
    this.instance.interceptors.response.use(
      (response: AxiosResponse) => {
        // 接口响应成功处理

        const res: any = response.data // 获取响应值

        // token失效
        if (res.code === 10021) {
          this.handleTokenExpiration() // 登出事件
        }
        //状态码不同处理
        // 状态码 0 表示请求成功
        else if (res.code !== 0) {
          console.log(response.data.msg)
          return showNotify(response.data.msg || '系统出错')
        }
        else {
          return response.data
        }
      },
      (error: AxiosError) => {
        // 接口请求失败处理
        let message: string = error.message

        // 重复请求
        if (message.includes('Duplicate request')) {
          showNotify({
            type: 'danger',
            // showClose: true,
            message: '数据正在处理，请勿频繁操作',
            duration: 3 * 1000,
          })
          return Promise.reject(error)
        }
        // 请求超时
        else if (message.includes('timeout of')) {
          message = '系统接口请求超时'
          this.removeOverTimeRequest()
        }
        // 其他错误
        else if (error.response?.status) {
          console.log(message, '-message')
          // message = errorCodeType(error.response?.status)
        }

        showNotify({
          type: 'danger',
          // showClose: true,
          message,
          duration: 3 * 1000,
        })
        return Promise.reject(error)
      }
    )
    // ========================================================================== 请求拦截器 - 结束 ============================================================================
  }

  // 统一处理登出事件
  // private ElMessageBox: any
  private handleTokenExpiration() {

      localStorage.clear()
      // router.replace('/')
    // })
    return showConfirmDialog({
      title: '提示',
      message:
        '当前页面已失效，请重新登录',
    })
      .then(() => {
        // on confirm
        localStorage.clear()
        // router.replace('/')
      })

  }

  // 对比 对象参数 是否一致
  private deepEqual(obj1: any, obj2: any): boolean {
    if (obj1 === obj2) return true
    if (
      typeof obj1 !== 'object' ||
      typeof obj2 !== 'object' ||
      obj1 == null ||
      obj2 == null
    )
      return false
    const keys1 = Object.keys(obj1)
    const keys2 = Object.keys(obj2)
    if (keys1.length !== keys2.length) return false
    for (const key of keys1) {
      if (!keys2.includes(key) || !this.deepEqual(obj1[key], obj2[key]))
        return false
    }
    return true
  }

  // 对比 数组参数 是否一致
  private isArrayEqual(arr1: any[], arr2: any[]): boolean {
    if (arr1.length !== arr2.length) return false
    const sortedArr1 = [...arr1].sort()
    const sortedArr2 = [...arr2].sort()
    for (let i = 0; i < sortedArr1.length; i++) {
      if (!this.deepEqual(sortedArr1[i], sortedArr2[i])) return false
    }
    return true
  }

  // 移除重复请求 只执行最后一次请求
  private addRequestQueue(config: InternalAxiosRequestConfig) {
    const queueItem = {
      url: config.url!, // 非空断言
      method: config.method!, // 非空断言
      createTime: Date.now(),
      params: Array.isArray(config.params)
        ? config.params
        : config.params || {},
      data: Array.isArray(config.data) ? config.data : config.data || {},
    }

    // 初次添加或检查是否有重复请求并决定是否取消
    if (this.requestQueue.length === 0) {
      config.cancelToken = new axios.CancelToken((cancel: Canceler) => {
        this.requestQueue.push({...queueItem, cancel})
      })
    } else {
      // 使用some方法来检查是否存在重复的请求，这样可以在找到第一个匹配项时立即停止循环
      const isDuplicate = this.requestQueue.some(
        (p) =>
          p.url === queueItem.url &&
          p.method === queueItem.method &&
          (Array.isArray(p.params)
            ? this.isArrayEqual(p.params, queueItem.params)
            : this.deepEqual(p.params, queueItem.params)) &&
          (Array.isArray(p.data)
            ? this.isArrayEqual(p.data, queueItem.data)
            : this.deepEqual(p.data, queueItem.data))
      )

      if (isDuplicate) {
        config.cancelToken = new axios.CancelToken((cancel: Canceler) => {
          cancel('Duplicate request')
        })
      } else {
        // 如果没有重复，则正常添加到队列
        config.cancelToken = new axios.CancelToken((cancel: Canceler) => {
          this.requestQueue.push({...queueItem, cancel})
        })
      }
    }
  }

  // 指定时间内只触发一次接口请求
  private removeRequestQueue(target: InternalAxiosRequestConfig) {
    const currentTime = Date.now() // 当前时间
    const validationTime = target.duplicateRequestValidationTime || 0 // 接口重复请求时间

    // 使用 filter 方法来移除符合条件的请求，这比直接修改数组更简洁且能避免循环中修改数组的问题
    this.requestQueue = this.requestQueue.filter((p, index) => {
      // 只有当请求URL、方法相同，且请求发生在指定时间范围内，才保留该请求
      const isDuplicateAndExpired =
        p.url === target.url &&
        p.method === target.method &&
        p.createTime &&
        currentTime - p.createTime <= validationTime

      // 如果是重复请求且已过期，则取消并从队列中移除
      if (!isDuplicateAndExpired) {
        p.cancel(`Duplicate request`)
      }
      // filter 会自动排除那些返回 false 的元素
      return isDuplicateAndExpired
    })
  }

  // 移除请求超时接口
  private removeOverTimeRequest() {
    const nowDate = Date.now()
    const timeout = Number(import.meta.env.VITE_APP_TIMEOUT) || 10000

    // 使用 filter 来移除超时的请求，filter 会返回一个新数组，包含所有未超时的请求
    this.requestQueue = this.requestQueue.filter((item) => {
      return nowDate - item.createTime < timeout
    })
  }

  // 返回一下
  getInterceptors() {
    return this.instance
  }
}